package org.luosl.webmagicx

import org.luosl.webmagicx.conf.{Component, DefaultConfValue, Props, SpiderConf}
import org.luosl.webmagicx.handler.BaseHandler
import org.luosl.webmagicx.listeners.GeneralPipelineListener
import org.luosl.webmagicx.pipeline.BasePipeline
import org.luosl.webmagicx.processor.BaseProcessor
import us.codecraft.webmagic.Spider
import us.codecraft.webmagic.scheduler.Scheduler

import scala.collection.JavaConverters._

/**
  * Created by luosl on 2017/12/21.
  */
object SpiderCreater {

  def createSpider(sc: SpiderConf):Spider = {
    // 创建 processor
    val processorComp:Component = sc.components.processor.getOrElse(
      Component(DefaultConfValue.processorClass,Map.empty[String,String])
    )
    val processor:BaseProcessor = createComponent(sc,processorComp)
      .asInstanceOf[BaseProcessor]

    // 创建 pipeline
    val pipelineComps:Seq[Component] = sc.components.pipelines
    val pipelines:Seq[BasePipeline] =  pipelineComps.map{ pipelineComp=>
      val pipeline:BasePipeline = createComponent(sc, pipelineComp).asInstanceOf[BasePipeline]
      pipeline.addListener(new GeneralPipelineListener(pipeline.getClass))
      pipeline
    }
    // 创建 handler
    val handlerComps:Seq[Component] = sc.components.handlers
    val handlers:Seq[BaseHandler] = handlerComps.map{ comp=>
      val handler:BaseHandler = createComponent(sc, comp).asInstanceOf[BaseHandler]
      handler
    }
    // 创建 scheduler
    val schedulerComp:Component = sc.components.scheduler.getOrElse(
      Component(DefaultConfValue.schedulerClass,Map.empty[String,String])
    )
    val scheduler:Scheduler = createComponent(sc, schedulerComp).asInstanceOf[Scheduler]
    // 创建spider
    val spider:Spider = Spider.create(processor)
      .startUrls(sc.startUrls.asJava)
      .thread(sc.attribute.threadNum)
      .setExitWhenComplete(true)
    // 为 spider 添加 pipeline
    pipelines.foreach(spider.addPipeline(_))
    handlers.foreach(spider.addHandler(_))
    spider.setScheduler(scheduler)
  }

  /**
    * 创建一个组件
    * @param sc sc
    * @param comp comp
    */
  private def createComponent(sc:SpiderConf, comp: Component): Any ={
    val clazz:Class[_] = Class.forName(comp.clazz)
    val props:Props = Props(comp.prop, sc.path, clazz.getSimpleName)
    clazz.getConstructor(classOf[SpiderConf], classOf[Props])
      .newInstance(sc,props)
  }

}
